#ifndef __SIGHANDLER_H__
#define __SIGHANDLER_H__

/* The SigHandler is in charge or handling signals for a processor,
 * and can logically be considered part of the Processor class, but
 * can be seperated because it only needs access to the CPU.
 */

#include <ucontext.h>
#include <signal.h>

#include "base/signals/SigContext.h"
#include "base/simtypes.h"
#include "util/Logger.h"
#include "util/Vector.h"

// a signal stack is much smaller than a normal stack for threads
// a small fixed configuration for signal stack is as follows
#define SIGNAL_STACK_SIZE (256*1024)
#define STACK_ALIGNMENT_SIZE 4

#if SIGNAL_STACK_SIZE <= SIGSTKSZ
#error SIGNAL_STACK_SIZE is less than platform recommended SIGSTKSZ
#endif

extern Pool* SignalStackPool;


class CPU;
class Checkpoint;
class Processor;

class SigHandler {
  public:
    NEW_DELETE_OPERATORS_H(SigHandler,NoSuper);
    SigHandler (CPU* cpu);
    ~SigHandler ();
    static void blockSignal (SigContext* sigContext);
    static void unblockSignal (SigContext* sigContext);
    void trampolineToSigHandler (SigContext* sigContext);
    void trampolineToKernel ();
    void cleanupState ();
    void sigreturn (ucontext_t* ctx);
    static void afterSignalHandler ();
    static bool isa_ext_sigexit (Processor* P, Reg arg0, Reg arg1, Reg* result);
    bool hasSignals ();

    inline bool isProcessing () {
        return !sigContexts.empty();
    }
    
    bool inSigContextsBounds (VA addr, size_t len) {
        Vector<SigContext*>::iterator i;
        for (i  = sigContexts.begin();
             i != sigContexts.end();
             i++)
        {
            SigContext* sigContext = *i;
            VA scStart = ADDR_UINT64(sigContext);
            VA scEnd   = scStart+sizeof(SigContext);
            if (scStart <= addr+len && 
                addr    <= scEnd) {
                return true;
            }
        }
        return false;
    }

    int getCurrentSignal () {
        ASSERT(isProcessing());
        return sigContexts[0]->signum;
    }

  private:
    Byte* stack_unaligned_start;
    Byte* stack_aligned_end;
    CPU* runningcpu;
    Checkpoint* savedcpu;

    /** 
        Vector of SigContexts to allow for nested signals
     */
    Vector<SigContext*> sigContexts;

    static void initializeClass ();
    static bool initializedClass;
};
#endif // __SIGHANDLER_H__
